﻿using NHibernate;
using SportStore.Core.Data;
using System;
using System.Data;

namespace SportStore.Core.NHibernate
{
    /// <summary>
    /// Implements the unit of work.
    /// </summary>
    public class UnitOfWork : IUnitOfWork
    {
        #region Constants and Fields

        private readonly ISession session;

        /// <summary>
        /// The transaction that is active on the current thread.
        /// </summary>
        [ThreadStatic]
        private static Transaction threadTransaction;

        #endregion

        #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the <see cref="UnitOfWork"/> class.
        /// </summary>
        /// <param name="session">
        /// The session.
        /// </param>
        public UnitOfWork(ISession session)
        {
            // When a unit of work is constructed, always make sure the recorded transaction on the current thread
            // is nulled out.
            threadTransaction = null;

            this.session = session;
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Begins a transaction.
        /// </summary>
        public IGenericTransaction BeginTransaction()
        {
            return this.BeginTransaction(IsolationLevel.ReadCommitted);
        }

        /// <summary>
        /// Begins a transaction with an isolation level.
        /// </summary>
        /// <param name="isolationLevel">
        /// The isolation Level.
        /// </param>
        public IGenericTransaction BeginTransaction(IsolationLevel isolationLevel)
        {
            // If there isn't a current transaction open on this thread, or its reference
            // count has reached 0 (i.e. it has been disposed as many times as it has been constructed)
            // then create a new one.
            if (threadTransaction == null || !threadTransaction.HasReferences)
            {
                threadTransaction = new Transaction(this.session.BeginTransaction(isolationLevel));
            }

            threadTransaction.IncrementReferenceCount();
            return threadTransaction;
        }

        /// <summary>
        /// Flushes changes to the database.
        /// </summary>
        public void Flush()
        {
            this.session.Flush();
        }

        /// <summary>
        /// Clears the current session.
        /// </summary>
        public void Clear()
        {
            this.session.Clear();
        }

        #endregion
    }
}
